home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre1.z / postgre1 / test / postfs / cp.c next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  8.1 KB  |  434 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.  The Berkeley software License Agreement
  4.  * specifies the terms and conditions for redistribution.
  5.  */
  6.  
  7. #ifndef lint
  8. char copyright[] =
  9. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  10.  All rights reserved.\n";
  11. #endif not lint
  12.  
  13. #ifndef lint
  14. static    char sccsid[] = "@(#)cp.c 1.1 90/03/23 SMI"; /* from UCB 4.13 10/11/85 */
  15. #endif not lint
  16.  
  17. /*
  18.  * cp
  19.  */
  20. #include <stdio.h>
  21. #include <sys/param.h>
  22. #include <sys/stat.h>
  23. #include <sys/dir.h>
  24. #include <sys/time.h>
  25. #include <sys/mman.h>
  26.  
  27. #ifndef MAXMAPSIZE
  28. #define    MAXMAPSIZE    (256*1024)
  29. #endif
  30.  
  31. int    iflag;
  32. int    rflag;
  33. int    pflag;
  34. int    zflag;
  35. char    *rindex();
  36. caddr_t    mmap();
  37.  
  38. main(argc, argv)
  39.     int argc;
  40.     char **argv;
  41. {
  42.     struct stat stb;
  43.     int rc, i;
  44.  
  45.     argc--, argv++;
  46.     while (argc > 0 && **argv == '-') {
  47.         (*argv)++;
  48.         while (**argv) switch (*(*argv)++) {
  49.  
  50.         case 'i':
  51.             iflag++; break;
  52.  
  53.         case 'R':
  54.         case 'r':
  55.             rflag++; break;
  56.  
  57.         case 'p':    /* preserve mtimes, atimes, and modes */
  58.             pflag++;
  59.             (void) umask(0);
  60.             break;
  61.  
  62.         default:
  63.             goto usage;
  64.         }
  65.         argc--; argv++;
  66.     }
  67.     if (argc < 2) 
  68.         goto usage;
  69.     if (argc > 2) {
  70.         if (stat(argv[argc-1], &stb) < 0)
  71.             goto usage;
  72.         if ((stb.st_mode&S_IFMT) != S_IFDIR) 
  73.             goto usage;
  74.     }
  75.     rc = 0;
  76.     for (i = 0; i < argc-1; i++)
  77.         rc |= copy(argv[i], argv[argc-1]);
  78.     exit(rc);
  79. usage:
  80.     (void) fprintf(stderr,
  81.         "Usage: cp [-ip] f1 f2; or: cp [-ipr] f1 ... fn d2\n");
  82.     exit(1);
  83.     /* NOTREACHED */
  84. }
  85.  
  86. copy(from, to)
  87.     char *from, *to;
  88. {
  89.     int fold, fnew, n, exists;
  90.     char *last, destname[MAXPATHLEN + 1], buf[MAXBSIZE];
  91.     struct stat stfrom, stto;
  92.     register caddr_t cp;
  93.     int mapsize, munmapsize;
  94.     register off_t filesize;
  95.     register off_t offset;
  96.  
  97.     fold = open(from, 0);
  98.     if (fold < 0) {
  99.         Perror(from);
  100.         return (1);
  101.     }
  102.     if (fstat(fold, &stfrom) < 0) {
  103.         Perror(from);
  104.         (void) close(fold);
  105.         return (1);
  106.     }
  107.     if (stat(to, &stto) >= 0 &&
  108.        (stto.st_mode&S_IFMT) == S_IFDIR) {
  109.         last = rindex(from, '/');
  110.         if (last) last++; else last = from;
  111.         if (strlen(to) + strlen(last) >= sizeof destname - 1) {
  112.             (void) fprintf(stderr, "cp: %s/%s: Name too long\n",
  113.                 to, last);
  114.             (void) close(fold);
  115.             return(1);
  116.         }
  117.         (void) sprintf(destname, "%s/%s", to, last);
  118.         to = destname;
  119.     }
  120.     if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) {
  121.         int fixmode = 0;    /* cleanup mode after rcopy */
  122.  
  123.         (void) close(fold);
  124.         if (stat(to, &stto) < 0) {
  125.             if (mkdir(to,
  126.                 ((int)stfrom.st_mode & 07777) | 0700) < 0) {
  127.                 Perror(to);
  128.                 return (1);
  129.             }
  130.             fixmode = 1;
  131.         } else if ((stto.st_mode&S_IFMT) != S_IFDIR) {
  132.             (void) fprintf(stderr, "cp: %s: Not a directory.\n",
  133.                 to);
  134.             return (1);
  135.         } else if (pflag)
  136.             fixmode = 1;
  137.         n = rcopy(from, to);
  138.         if (fixmode)
  139.             (void) chmod(to, (int)stfrom.st_mode & 07777);
  140.         return (n);
  141.     }
  142.  
  143.     if ((stfrom.st_mode&S_IFMT) == S_IFDIR) {
  144.         (void) close(fold);
  145.         (void) fprintf(stderr, "cp: %s: Is a directory (not copied).\n",
  146.             from);
  147.         return (1);
  148.     }
  149.  
  150.     exists = stat(to, &stto) == 0;
  151.     if (exists) {
  152.         if (stfrom.st_dev == stto.st_dev &&
  153.            stfrom.st_ino == stto.st_ino) {
  154.             (void) fprintf(stderr,
  155.                 "cp: %s and %s are identical (not copied).\n",
  156.                     from, to);
  157.             (void) close(fold);
  158.             return (1);
  159.         }
  160.         if (iflag && isatty(fileno(stdin))) {
  161.             int i, c;
  162.  
  163.             (void) fprintf (stderr, "overwrite %s? ", to);
  164.             i = c = getchar();
  165.             while (c != '\n' && c != EOF)
  166.                 c = getchar();
  167.             if (i != 'y') {
  168.                 (void) close(fold);
  169.                 return(1);
  170.             }
  171.         }
  172.     }
  173.     fnew = creat(to, (int)stfrom.st_mode & 07777);
  174.     if (fnew < 0) {
  175.         Perror(to);
  176.         (void) close(fold); return(1);
  177.     }
  178.     if (exists && pflag)
  179.         (void) fchmod(fnew, (int)stfrom.st_mode & 07777);
  180.  
  181.     zopen(fnew, zflag);
  182.  
  183.     if ((stfrom.st_mode & S_IFMT) == S_IFREG) {
  184.         /*
  185.          * Determine size of initial mapping.  This will determine
  186.          * the size of the address space chunk we work with.  This
  187.          * initial mapping size will be used to perform munmap() in
  188.          * the future.
  189.          */
  190.         mapsize = MAXMAPSIZE;
  191.         if (stfrom.st_size < mapsize)
  192.             mapsize = stfrom.st_size;
  193.         munmapsize = mapsize;
  194.  
  195.         /*
  196.          * Mmap time!
  197.          */
  198.         cp = mmap((caddr_t)NULL, mapsize, PROT_READ, MAP_SHARED, fold,
  199.             (off_t)0);
  200.         if (cp == (caddr_t)-1)
  201.             mapsize = 0;    /* I guess we can't mmap today */
  202.     } else
  203.         mapsize = 0;        /* can't mmap non-regular files */
  204.  
  205.     if (mapsize != 0) {
  206.         offset = 0;
  207.         filesize = stfrom.st_size;
  208. #ifdef MC_ADVISE
  209.         (void) madvise(cp, mapsize, MADV_SEQUENTIAL);
  210. #endif
  211.         for (;;) {
  212.             if (zwrite(fnew, cp, mapsize) < 0) {
  213.                 Perror(to);
  214.                 (void) close(fold);
  215.                 (void) close(fnew);
  216.                 (void) munmap(cp, munmapsize);
  217.                 return (1);
  218.             }
  219.             filesize -= mapsize;
  220.             if (filesize == 0)
  221.                 break;
  222.             offset += mapsize;
  223.             if (filesize < mapsize)
  224.                 mapsize = filesize;
  225.             if (mmap(cp, mapsize, PROT_READ, MAP_SHARED | MAP_FIXED,
  226.                 fold, offset) == (caddr_t)-1) {
  227.                 Perror(from);
  228.                 (void) close(fold);
  229.                 (void) close(fnew);
  230.                 (void) munmap(cp, munmapsize);
  231.                 return (1);
  232.             }
  233. #ifdef MC_ADVISE
  234.             (void) madvise(cp, mapsize, MADV_SEQUENTIAL);
  235. #endif
  236.         }
  237.         (void) munmap(cp, munmapsize);
  238.     } else {
  239.         for (;;) {
  240.             n = read(fold, buf, sizeof buf);
  241.             if (n == 0)
  242.                 break;
  243.             if (n < 0) {
  244.                 Perror(from);
  245.                 (void) close(fold);
  246.                 (void) close(fnew);
  247.                 return (1);
  248.             }
  249.             if (zwrite(fnew, buf, n) < 0) {
  250.                 Perror(to);
  251.                 (void) close(fold);
  252.                 (void) close(fnew);
  253.                 return (1);
  254.             }
  255.         }
  256.     }
  257.     (void) close(fold);
  258.     if (zclose(fnew) < 0) {
  259.         Perror(to);
  260.         (void) close(fnew);
  261.         return (1);
  262.     }
  263.     if (close(fnew) < 0) {
  264.         Perror(to);
  265.         return (1);
  266.     }
  267.     if (pflag)
  268.         return (setimes(to, &stfrom));
  269.     return (0);
  270. }
  271.  
  272. rcopy(from, to)
  273.     char *from, *to;
  274. {
  275.     DIR *fold = opendir(from);
  276.     struct direct *dp;
  277.     struct stat statb;
  278.     int errs = 0;
  279.     char fromname[MAXPATHLEN + 1];
  280.  
  281.     if (fold == 0 || (pflag && fstat(fold->dd_fd, &statb) < 0)) {
  282.         Perror(from);
  283.         return (1);
  284.     }
  285.     for (;;) {
  286.         dp = readdir(fold);
  287.         if (dp == 0) {
  288.             (void) closedir(fold);
  289.             if (pflag)
  290.                 return (setimes(to, &statb) + errs);
  291.             return (errs);
  292.         }
  293.         if (dp->d_ino == 0)
  294.             continue;
  295.         if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  296.             continue;
  297.         if (strlen(from)+1+strlen(dp->d_name) >= sizeof fromname - 1) {
  298.             (void) fprintf(stderr, "cp: %s/%s: Name too long\n",
  299.                 from, dp->d_name);
  300.             errs++;
  301.             continue;
  302.         }
  303.         (void) sprintf(fromname, "%s/%s", from, dp->d_name);
  304.         errs += copy(fromname, to);
  305.     }
  306. }
  307.  
  308. int
  309. setimes(path, statp)
  310.     char *path;
  311.     struct stat *statp;
  312. {
  313.     struct timeval tv[2];
  314.     
  315.     tv[0].tv_sec = statp->st_atime;
  316.     tv[1].tv_sec = statp->st_mtime;
  317.     tv[0].tv_usec = tv[1].tv_usec = 0;
  318.     if (utimes(path, tv) < 0) {
  319.         Perror(path);
  320.         return (1);
  321.     }
  322.     return (0);
  323. }
  324.  
  325. Perror(s)
  326.     char *s;
  327. {
  328.  
  329.     (void) fprintf(stderr, "cp: ");
  330.     perror(s);
  331. }
  332.  
  333.  
  334. /*
  335.  * sparse file support
  336.  */
  337.  
  338. #include <errno.h>
  339. #include <sys/file.h>
  340.  
  341. static int zbsize;
  342. static int zlastseek;
  343. off_t lseek();
  344.  
  345. /* is it ok to try to create holes? */
  346. zopen(fd, flag)
  347.     int fd;
  348. {
  349.     struct stat st;
  350.  
  351.     zbsize = 0;
  352.     zlastseek = 0;
  353.  
  354.     if (flag &&
  355.         fstat(fd, &st) == 0 &&
  356.         (st.st_mode & S_IFMT) == S_IFREG)
  357.         zbsize = st.st_blksize;
  358. }
  359.  
  360. /* write and/or seek */
  361. zwrite(fd, buf, nbytes)
  362.     int fd;
  363.     register char *buf;
  364.     register int nbytes;
  365. {
  366.     register int block = zbsize ? zbsize : nbytes;
  367.  
  368.     do {
  369.         if (block > nbytes)
  370.             block = nbytes;
  371.         nbytes -= block;
  372.  
  373.         if (!zbsize || notzero(buf, block)) {
  374.             register int n, count = block;
  375.  
  376.             do {
  377.                 if ((n = write(fd, buf, count)) < 0)
  378.                     return -1;
  379.                 buf += n;
  380.             } while ((count -= n) > 0);
  381.             zlastseek = 0;
  382.         }
  383.         else {
  384.             if (lseek(fd, (off_t) block, L_INCR) < 0)
  385.                 return -1;
  386.             buf += block;
  387.             zlastseek = 1;
  388.         }
  389.     } while (nbytes > 0);
  390.  
  391.     return 0;
  392. }
  393.  
  394. /* write last byte of file if necessary */
  395. zclose(fd)
  396.     int fd;
  397. {
  398.     zbsize = 0;
  399.  
  400.     if (zlastseek &&
  401.         (lseek(fd, (off_t) -1, L_INCR) < 0 ||
  402.         zwrite("", 1) < 0))
  403.         return -1;
  404.      else
  405.         return 0;
  406. }
  407.  
  408. /* return true if buffer is not all zeros */
  409. notzero(p, n)
  410.     register char *p;
  411.     register int n;
  412. {
  413.     register int result = 0;
  414.  
  415.     while ((int) p & 3 && --n >= 0)
  416.         result |= *p++;
  417.  
  418.     while ((n -= 4 * sizeof (int)) >= 0) {
  419.         result |= ((int *) p)[0];
  420.         result |= ((int *) p)[1];
  421.         result |= ((int *) p)[2];
  422.         result |= ((int *) p)[3];
  423.         if (result)
  424.             return result;
  425.         p += 4 * sizeof (int);
  426.     }
  427.     n += 4 * sizeof (int);
  428.  
  429.     while (--n >= 0)
  430.         result |= *p++;
  431.  
  432.     return result;    
  433. }
  434.